﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using SPMS.Log.Core;

namespace SPMS.Log.Formatter
{
    /// <summary>
    /// XML日志格式化器
    /// </summary>
    /// <remarks>用于将日志信息格式化为XML描述形式</remarks>
    /// <history>
    /// [zanezeng]               2009/9/28 11:24    创建
    /// </history>
    public class XmlFormatter : AbstractFormatter
    {
        #region ---Protected Method

        /// <summary>
        /// 给定的日志条目写成XML数据
        /// </summary>
        /// <param name="writer">用其进行写操作的<see cref="XmlTextWriter"/>对象。</param>
        /// <param name="entry">要写成XML数据的日志条目对象</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:28    创建
        /// </history>
        protected virtual void WriteEntryXml( XmlTextWriter writer, LogEntry entry )
        {
            //写入事件开始标记
            writer.WriteStartElement( TAG_EVENT );

            //写入时间标记
            writer.WriteStartElement( TAG_TIME );

            //写入值
            writer.WriteString( this.FormatObject( entry.Timestamp ) );

            //写入结束标记
            writer.WriteEndElement();

            //写入级别标记
            writer.WriteStartElement( TAG_LEVEL );

            //写入值
            writer.WriteString( entry.Level.DisplayName );

            //写入结束标记
            writer.WriteEndElement();

            //写入记录器标记
            writer.WriteStartElement( TAG_LOGGER );

            //写入值
            if (!string.IsNullOrEmpty( entry.LoggerName ))
            {
                writer.WriteString( entry.LoggerName );
            }

            //写入结束标记
            writer.WriteEndElement();

            //写入应用程序域标记
            writer.WriteStartElement( TAG_DOMAIN );

            //写入值
            if (!string.IsNullOrEmpty( entry.DomainName ))
            {
                writer.WriteString( entry.DomainName );
            }

            //写入结束标记
            writer.WriteEndElement();

            //写入线程标记
            writer.WriteStartElement( TAG_THREAD );

            //写入值
            if (!string.IsNullOrEmpty( entry.ThreadName ))
            {
                writer.WriteString( entry.ThreadName );
            }

            //写入结束标记
            writer.WriteEndElement();

            //写入用户标记
            writer.WriteStartElement( TAG_USERNAME );

            //写入值
            if (!string.IsNullOrEmpty( entry.UserName ))
            {
                writer.WriteString( entry.UserName );
            }

            //写入结束标记
            writer.WriteEndElement();

            //写入用户标识标记
            writer.WriteStartElement( TAG_IDENTITY );

            //写入值
            if (!string.IsNullOrEmpty( entry.Identity ))
            {
                writer.WriteString( entry.Identity );
            }

            //写入结束标记
            writer.WriteEndElement();

            //写入消息标记
            writer.WriteStartElement( TAG_MESSAGE );

            //写入值
            writer.WriteCData( this.FormatObject( entry.Message ) );

            //写入结束标记
            writer.WriteEndElement();

            //写入类型标记
            writer.WriteStartElement( TAG_TYPE );

            //写入值
            writer.WriteString( entry.TypeName );

            //写入结束标记
            writer.WriteEndElement();

            //写入方法标记
            writer.WriteStartElement( TAG_METHOD );

            //写入值
            writer.WriteString( entry.MethodName );

            //写入结束标记
            writer.WriteEndElement();

            //写入文件标记
            writer.WriteStartElement( TAG_FILE );

            //写入值
            writer.WriteString( entry.FileName );

            //写入结束标记
            writer.WriteEndElement();

            //写入行号标记
            writer.WriteStartElement( TAG_LINE );

            //写入值
            writer.WriteValue( entry.LineNumber );

            //写入结束标记
            writer.WriteEndElement();

            //写入列号标记
            writer.WriteStartElement( TAG_COLUMN );

            //写入值
            writer.WriteValue( entry.ColumnNumber );

            //写入结束标记
            writer.WriteEndElement();

            //循环写入附加信息
            if (entry.HasExtendedProperty)
            {
                //循环写入附加信息
                foreach (KeyValuePair<string, object> item in entry.ExtendedProperties)
                {
                    //写入列号标记
                    writer.WriteStartElement( TAG_EXTENDED + item.Key );

                    //写入值
                    writer.WriteCData( this.FormatObject( item.Value ) );

                    //写入结束标记
                    writer.WriteEndElement();
                }
            }

            //写入异常标记
            writer.WriteStartElement( TAG_EXCEPTION );

            //写入值
            writer.WriteCData( this.FormatObject( entry.Exception ) );

            //写入结束标记
            writer.WriteEndElement();

            //写入结束标记
            writer.WriteEndElement();
        }

        /// <summary>
        /// 将给定的日志条目格式化为一个有序的字符串序列
        /// </summary>
        /// <param name="entry">要进行格式化的日志记录</param>
        /// <returns>描述给定日志记录的一个有序的字符串序列</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/13 10:19    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/13 10:20    创建
        /// </history>
        protected override string FormatEntry( LogEntry entry )
        {
            //创建字符串写入器
            using (StringWriter baseWriter = new StringWriter( this.FormatProvider ))
            {
                //创建XML写入器
                XmlTextWriter writer = new XmlTextWriter( baseWriter );

                //写入XML数据
                this.WriteEntryXml( writer, entry );

                //关闭写入器
                writer.Close();

                //强制将内部缓冲区中保留的所有批注数据写入基础存储设备中
                baseWriter.Flush();

                //返回数据
                return baseWriter.GetStringBuilder().ToString();
            }
        }

        #endregion

        #region ---Const

        /// <summary>
        /// 事件标记
        /// </summary>
        private const string TAG_EVENT = "event";

        /// <summary>
        /// 日志记录器标记
        /// </summary>
        private const string TAG_LOGGER = "logger";

        /// <summary>
        /// 级别标记
        /// </summary>
        private const string TAG_LEVEL = "level";

        /// <summary>
        /// 时间标记
        /// </summary>
        private const string TAG_TIME = "time";

        /// <summary>
        /// 消息标记
        /// </summary>
        private const string TAG_MESSAGE = "message";

        /// <summary>
        /// 异常标记
        /// </summary>
        private const string TAG_EXCEPTION = "exception";

        /// <summary>
        /// 用户名称标记
        /// </summary>
        private const string TAG_USERNAME = "username";

        /// <summary>
        /// 用户标记名称标记
        /// </summary>
        private const string TAG_IDENTITY = "identity";

        /// <summary>
        /// 应用程序域标记
        /// </summary>
        private const string TAG_DOMAIN = "domain";

        /// <summary>
        /// 线程标记
        /// </summary>
        private const string TAG_THREAD = "thread";

        /// <summary>
        /// 类型名称
        /// </summary>
        private const string TAG_TYPE = "type";

        /// <summary>
        /// 方法名称
        /// </summary>
        private const string TAG_METHOD = "method";

        /// <summary>
        /// 文件标记
        /// </summary>
        private const string TAG_FILE = "file";

        /// <summary>
        /// 行号标记
        /// </summary>
        private const string TAG_LINE = "line";

        /// <summary>
        /// 行号标记
        /// </summary>
        private const string TAG_COLUMN = "column";

        /// <summary>
        /// 扩展信息
        /// </summary>
        private const string TAG_EXTENDED = "extend:";

        #endregion
    }
}
